using System;
using LocalOverride.Fiddler.UrlMapping;
using NUnit.Framework;
using System.Collections.Generic;

namespace LocalOverride.Tests.UrlMapping
{
    [TestFixture]
    public class MappingRegistryTests
    {
        [Test]
        public void GetMapping_WhenContainsExactUrl_ReturnsPath()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(
                new SingleFileMapping(
                    new Uri("http://www.test.com"), @"c:\temp.html"
                ));

            // Act
            var requestUri = new Uri("http://www.test.com");
            var result = mapping.GetMapping(requestUri);

            // Assert
            const string expectedFilePath = @"c:\temp.html";
            Assert.AreEqual(expectedFilePath, result.LocalFile);
        }

        [Test]
        public void Will_Return_Results_ForEscapedUrls()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(
                new DirectoryMapping(
                    new Uri("http://www.test.com/Style Library/"), @"c:\Style Library"
                ));

            // Act
            var requestUri = new Uri("http://www.test.com/Style%20Library/test.css");
            var result = mapping.GetMapping(requestUri);

            // Assert
            const string expectedFilePath = @"c:\Style Library\test.css";
            Assert.AreEqual(expectedFilePath, result.LocalFile);
        }

        [Test]
        public void GetMapping_WhenContainsExactUrl_IgnoresQueryStringAndReturnsPath()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(new SingleFileMapping(
                    new Uri("http://www.test.com"), @"c:\temp.html"
                ));

            // Act
            var requestUri = new Uri("http://www.test.com?blah=test&dd=33");
            var result = mapping.GetMapping(requestUri);

            // Assert
            const string expectedFilePath = @"c:\temp.html";
            Assert.AreEqual(expectedFilePath, result.LocalFile);
        }

        [Test]
        public void GetMapping_WhenContainsNoMappings_ReturnsNull()
        {
            // Arrange
            var mapping = new MappingRegistry();

            // Act
            const string hostName = "http://www.test.com";
            var uri = new Uri(hostName);
            var result = mapping.GetMapping(uri);

            // Assert
            Assert.AreEqual(MappingResult.NoMapping, result);
        }

        [Test]
        public void GetMapping_WhenContainsRootUrlDirectoryEntry_ReturnsEquivalentPath()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(
                new DirectoryMapping(
                    new Uri("http://www.test.com/")
                    , @"c:\temp")
                );

            // Act
            var requestUri = new Uri("http://www.test.com/blah.html");
            var result = mapping.GetMapping(requestUri);

            // Assert
            const string expectedFilePath = @"c:\temp\blah.html";
            Assert.AreEqual(expectedFilePath, result.LocalFile);
        }

        [Test]
        public void GetMapping_SetsDownloadMissingFileToTrue_WhenMappingSaysDownloadMissingFile()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(
                new DirectoryMapping(
                    new Uri("http://www.test.com/")
                    , @"c:\temp", new string[0], true, null, new string[0], null)
                );

            // Act
            var requestUri = new Uri("http://www.test.com/blah.html");
            var result = mapping.GetMapping(requestUri);

            // Assert
            Assert.IsTrue(result.DownloadMissingFile);
        }

        [Test]
        public void GetMapping_WhenContainsRootUrlDirectoryEntry_IgnoresQueryStringAndReturnsEquivalentPath()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(
                new DirectoryMapping(
                    new Uri("http://www.test.com/")
                    , @"c:\temp")
                );

            // Act
            var requestUri = new Uri("http://www.test.com/blah.html?blah=test&asfdsffs=44");
            var result = mapping.GetMapping(requestUri);

            // Assert
            const string expectedFilePath = @"c:\temp\blah.html";
            Assert.AreEqual(expectedFilePath, result.LocalFile);
        }

        [Test]
        public void GetMapping_WhenContainsDirectoryEntry_ReturnsPathForMatchingPath()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(
               new DirectoryMapping(
                   new Uri("http://www.test.com/foo")
                   , @"c:\temp")
               );

            // Act
            var requestUri = new Uri("http://www.test.com/foo/blah.html");
            var result = mapping.GetMapping(requestUri);

            // Assert
            const string expectedFilePath = @"c:\temp\blah.html";
            Assert.AreEqual(expectedFilePath, result.LocalFile);
        }

        [Test]
        public void GetMapping_WhenContainsDirectoryEntry_ReturnsNullForNonMatchingPath()
        {
            // Arrange
            var mapping = new MappingRegistry();
            mapping.AddMapping(
               new DirectoryMapping(
                   new Uri("http://www.test.com/foo")
                   , @"c:\temp", new List<string>(), false, null, new string[0], null)
               );

            // Act
            var requestUri = new Uri("http://www.test.com/bar/blah.html");
            var result = mapping.GetMapping(requestUri);

            // Assert
            Assert.AreEqual(MappingResult.NoMapping, result);
        }

        [Test]
        public void GetMapping_WhenContainsPattern_DoesNotReturnUnmatchingUrl()
        {
            // Arrange
            MappingRegistry mapping = GetCssOnlyMappingRegistry();

            // Act
            var requestUri = new Uri("http://www.test.com/foo/blah.html");
            var result = mapping.GetMapping(requestUri);

            // Assert
            Assert.AreEqual(MappingResult.NoMapping, result);
        }

        [Test]
        public void GetMapping_WhenContainsExtensionElsewhere_DoesNotReturnUnmatchingUrl()
        {
            // Arrange
            MappingRegistry mapping = GetCssOnlyMappingRegistry();

            // Act
            var requestUri = new Uri("http://www.test.com/foo/css.html");
            var result = mapping.GetMapping(requestUri);

            // Assert
            Assert.AreEqual(MappingResult.NoMapping, result);
        }

        [Test]
        public void GetMapping_WhenContainsExtensionInQueryString_DoesNotReturnUnmatchingUrl()
        {
            // Arrange
            MappingRegistry mapping = GetCssOnlyMappingRegistry();

            // Act
            var requestUri = new Uri("http://www.test.com/foo/blah.html?test.css");
            var result = mapping.GetMapping(requestUri);

            // Assert
            Assert.AreEqual(MappingResult.NoMapping, result);
        }

        [Test]
        public void GetMapping_WhenContainsPattern_ReturnsMatchingUrl()
        {
            // Arrange
            MappingRegistry mapping = GetCssOnlyMappingRegistry();

            // Act
            var requestUri = new Uri("http://www.test.com/foo/blah.css");
            var result = mapping.GetMapping(requestUri);

            // Assert
            Assert.AreEqual(@"c:\temp\blah.css", result.LocalFile);
        }

        [Test]
        public void GetMapping_WhenDirectoryRoot_ReturnsDefaultFileName()
        {
            // Arrange
            var mapping = new MappingRegistry();
            var directoryMapping = new DirectoryMapping(
                new Uri("http://www.test.com/")
                , @"c:\temp",
                new List<string>(), false, "default.html", new string[0], null);
            mapping.AddMapping(directoryMapping);

            // Act
            var requestUri = new Uri("http://www.test.com/foo/?test.com");
            var result = mapping.GetMapping(requestUri);

            // Assert
            Assert.AreEqual(@"c:\temp\foo\default.html", result.LocalFile);
        }

        private MappingRegistry GetCssOnlyMappingRegistry()
        {
            var mapping = new MappingRegistry();
            var directoryMapping = new DirectoryMapping(
                new Uri("http://www.test.com/foo")
                , @"c:\temp",
                new List<string> { @"css" }, false, null, new string[0], null);
            mapping.AddMapping(directoryMapping);
            return mapping;
        }
    }
}